home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / cc / g++.c < prev    next >
C/C++ Source or Header  |  1993-12-02  |  12KB  |  507 lines

  1. /* G++ preliminary semantic processing for the compiler driver.
  2.    Copyright (C) 1993 Free Software Foundation, Inc.
  3.    Contributed by Brendan Kehoe (brendan@cygnus.com).
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU CC is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU CC; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* This program is a wrapper to the main `gcc' driver.  For GNU C++,
  22.    we need to do two special things: a) append `-lg++' in situations
  23.    where it's appropriate, to link in libg++, and b) add `-xc++'..`-xnone'
  24.    around file arguments named `foo.c' or `foo.i'.  So, we do all of
  25.    this semantic processing then just exec gcc with the new argument
  26.    list.
  27.  
  28.    We used to do all of this in a small shell script, but many users
  29.    found the performance of this as a shell script to be unacceptable.
  30.    In situations where your PATH has a lot of NFS-mounted directories,
  31.    using a script that runs sed and other things would be a nasty
  32.    performance hit.  With this program, we never search the PATH at all.  */
  33.  
  34. #include "config.h"
  35. #include "gvarargs.h"
  36. #include <stdio.h>
  37. #include <sys/types.h>
  38. #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
  39.  
  40. /* Defined to the name of the compiler; if using a cross compiler, the
  41.    Makefile should compile this file with the proper name
  42.    (e.g., "i386-aout-gcc").  */
  43. #ifndef GCC_NAME
  44. #define GCC_NAME "gcc"
  45. #endif
  46.  
  47. /* This bit is set if we saw a `-xfoo' language specification.  */
  48. #define LANGSPEC    (1<<1)
  49. /* This bit is set if they did `-lm' or `-lmath'.  */
  50. #define MATHLIB        (1<<2)
  51.  
  52. /* On MSDOS, write temp files in current dir
  53.    because there's no place else we can expect to use.  */
  54. #if __MSDOS__
  55. #ifndef P_tmpdir
  56. #define P_tmpdir "."
  57. #endif
  58. #ifndef R_OK
  59. #define R_OK 4
  60. #define W_OK 2
  61. #define X_OK 1
  62. #endif
  63. #endif
  64.  
  65. extern int errno, sys_nerr;
  66. #if defined(bsd4_4)
  67. extern const char *const sys_errlist[];
  68. #else
  69. extern char *sys_errlist[];
  70. #endif
  71.  
  72. /* Name with which this program was invoked.  */
  73. static char *programname;
  74.  
  75. #ifdef HAVE_VPRINTF
  76. /* Output an error message and exit */
  77.  
  78. static void
  79. fatal (va_alist)
  80.      va_dcl
  81. {
  82.   va_list ap;
  83.   char *format;
  84.  
  85.   va_start (ap);
  86.   format = va_arg (ap, char *);
  87.   fprintf (stderr, "%s: ", programname);
  88.   vfprintf (stderr, format, ap);
  89.   va_end (ap);
  90.   fprintf (stderr, "\n");
  91. #if 0
  92.   /* XXX Not needed for g++ driver.  */
  93.   delete_temp_files ();
  94. #endif
  95.   exit (1);
  96. }
  97.  
  98. static void
  99. error (va_alist)
  100.      va_dcl
  101. {
  102.   va_list ap;
  103.   char *format;
  104.  
  105.   va_start (ap);
  106.   format = va_arg (ap, char *);
  107.   fprintf (stderr, "%s: ", programname);
  108.   vfprintf (stderr, format, ap);
  109.   va_end (ap);
  110.  
  111.   fprintf (stderr, "\n");
  112. }
  113.  
  114. #else /* not HAVE_VPRINTF */
  115.  
  116. static void
  117. error (msg, arg1, arg2)
  118.      char *msg, *arg1, *arg2;
  119. {
  120.   fprintf (stderr, "%s: ", programname);
  121.   fprintf (stderr, msg, arg1, arg2);
  122.   fprintf (stderr, "\n");
  123. }
  124.  
  125. static void
  126. fatal (msg, arg1, arg2)
  127.      char *msg, *arg1, *arg2;
  128. {
  129.   error (msg, arg1, arg2);
  130. #if 0
  131.   /* XXX Not needed for g++ driver.  */
  132.   delete_temp_files ();
  133. #endif
  134.   exit (1);
  135. }
  136.  
  137. #endif /* not HAVE_VPRINTF */
  138.  
  139. /* More 'friendly' abort that prints the line and file.
  140.    config.h can #define abort fancy_abort if you like that sort of thing.  */
  141.  
  142. void
  143. fancy_abort ()
  144. {
  145.   fatal ("Internal g++ abort.");
  146. }
  147.  
  148. char *
  149. xmalloc (size)
  150.      unsigned size;
  151. {
  152.   register char *value = (char *) malloc (size);
  153.   if (value == 0)
  154.     fatal ("virtual memory exhausted");
  155.   return value;
  156. }
  157.  
  158. /* Return a newly-allocated string whose contents concatenate those
  159.    of s1, s2, s3.  */
  160. static char *
  161. concat (s1, s2, s3)
  162.      char *s1, *s2, *s3;
  163. {
  164.   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  165.   char *result = xmalloc (len1 + len2 + len3 + 1);
  166.  
  167.   strcpy (result, s1);
  168.   strcpy (result + len1, s2);
  169.   strcpy (result + len1 + len2, s3);
  170.   *(result + len1 + len2 + len3) = 0;
  171.  
  172.   return result;
  173. }
  174.  
  175. static void
  176. pfatal_with_name (name)
  177.      char *name;
  178. {
  179.   char *s;
  180.  
  181.   if (errno < sys_nerr)
  182.     s = concat ("%s: ", sys_errlist[errno], "");
  183.   else
  184.     s = "cannot open %s";
  185.   fatal (s, name);
  186. }
  187.  
  188. #ifdef __MSDOS__
  189. /* This is the common prefix we use to make temp file names.  */
  190. char *temp_filename;
  191.  
  192. /* Length of the prefix.  */
  193. int temp_filename_length;
  194.  
  195. /* Compute a string to use as the base of all temporary file names.  */
  196. static char *
  197. choose_temp_base_try (try, base)
  198. char *try;
  199. char *base;
  200. {
  201.   char *rv;
  202.   if (base)
  203.     rv = base;
  204.   else if (try == (char *)0)
  205.     rv = 0;
  206.   else if (access (try, R_OK | W_OK) != 0)
  207.     rv = 0;
  208.   else
  209.     rv = try;
  210.   return rv;
  211. }
  212.  
  213. static void
  214. choose_temp_base ()
  215. {
  216.   char *base = 0;
  217.   int len;
  218.  
  219.   base = choose_temp_base_try (getenv ("TMPDIR"), base);
  220.   base = choose_temp_base_try (getenv ("TMP"), base);
  221.   base = choose_temp_base_try (getenv ("TEMP"), base);
  222.  
  223. #ifdef P_tmpdir
  224.   base = choose_temp_base_try (P_tmpdir, base);
  225. #endif
  226.  
  227.   base = choose_temp_base_try ("/usr/tmp", base);
  228.   base = choose_temp_base_try ("/tmp", base);
  229.  
  230.   /* If all else fails, use the current directory! */  
  231.   if (base == (char *)0)
  232.     base = "./";
  233.  
  234.   len = strlen (base);
  235.   temp_filename = xmalloc (len + sizeof("/ccXXXXXX"));
  236.   strcpy (temp_filename, base);
  237.   if (len > 0 && temp_filename[len-1] != '/')
  238.     temp_filename[len++] = '/';
  239.   strcpy (temp_filename + len, "ccXXXXXX");
  240.  
  241.   mktemp (temp_filename);
  242.   temp_filename_length = strlen (temp_filename);
  243.   if (temp_filename_length == 0)
  244.     abort ();
  245. }
  246.  
  247. static void
  248. perror_exec (name)
  249.      char *name;
  250. {
  251.   char *s;
  252.  
  253.   if (errno < sys_nerr)
  254.     s = concat ("installation problem, cannot exec %s: ",
  255.         sys_errlist[errno], "");
  256.   else
  257.     s = "installation problem, cannot exec %s";
  258.   error (s, name);
  259. }
  260.  
  261. /* This is almost exactly what's in gcc.c:pexecute for MSDOS.  */
  262. void
  263. run_dos (program, argv)
  264.      char *program;
  265.      char *argv[];
  266. {
  267.   char *scmd, *rf;
  268.   FILE *argfile;
  269.   int i;
  270.  
  271.   choose_temp_base (); /* not in gcc.c */
  272.  
  273.   scmd = (char *) malloc (strlen (program) + strlen (temp_filename) + 10);
  274.   rf = scmd + strlen (program) + 6;
  275.   sprintf (scmd, "%s.exe @%s.gp", program, temp_filename);
  276.  
  277.   argfile = fopen (rf, "w");
  278.   if (argfile == 0)
  279.     pfatal_with_name (rf);
  280.  
  281.   for (i=1; argv[i]; i++)
  282.     {
  283.       char *cp;
  284.       for (cp = argv[i]; *cp; cp++)
  285.     {
  286.       if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
  287.         fputc ('\\', argfile);
  288.       fputc (*cp, argfile);
  289.     }
  290.       fputc ('\n', argfile);
  291.     }
  292.   fclose (argfile);
  293.  
  294.   i = system (scmd);
  295.  
  296.   remove (rf);
  297.   
  298.   if (i == -1)
  299.     perror_exec (program);
  300. }
  301. #endif /* __MSDOS__ */
  302.  
  303. int
  304. main (argc, argv)
  305.      int argc;
  306.      char **argv;
  307. {
  308.   register int i, j = 0;
  309.   register char *p;
  310.   int (*fn)();
  311.   int verbose = 0;
  312.  
  313.   /* This will be NULL if we encounter a situation where we should not
  314.      link in libg++.  */
  315.   char *library = "-lg++";
  316.  
  317.   /* Used to track options that take arguments, so we don't go wrapping
  318.      those with -xc++/-xnone.  */
  319.   char *quote = NULL;
  320.  
  321.   /* The new argument list will be contained in this.  */
  322.   char **arglist;
  323.  
  324.   /* The name of the compiler we will want to run---by default, it
  325.      will be the definition of `GCC_NAME', e.g., `gcc'.  */
  326.   char *gcc = GCC_NAME;
  327.  
  328.   /* Non-zero if we saw a `-xfoo' language specification on the
  329.      command line.  Used to avoid adding our own -xc++ if the user
  330.      already gave a language for the file.  */
  331.   int saw_speclang = 0;
  332.  
  333.   /* Non-zero if we saw `-lm' or `-lmath' on the command line.  */
  334.   int saw_math = 0;
  335.  
  336.   /* The number of arguments being added to what's in argv.  By
  337.      default it's one new argument (adding `-lg++').  We use this
  338.      to track the number of times we've inserted -xc++/-xnone as well.  */
  339.   int added = 1;
  340.  
  341.   /* An array used to flag each argument that needs a bit set for
  342.      LANGSPEC or MATHLIB.  */
  343.   int *args;
  344.  
  345.   p = argv[0] + strlen (argv[0]);
  346.   while (p != argv[0] && p[-1] != '/')
  347.     --p;
  348.   programname = p;
  349.  
  350.   if (argc == 1)
  351.     fatal ("No input files specified.\n");
  352.  
  353. #ifndef __MSDOS__
  354.   /* We do a little magic to find out where the main gcc executable
  355.      is.  If they ran us as /usr/local/bin/g++, then we will look
  356.      for /usr/local/bin/gcc; similarly, if they just ran us as `g++',
  357.      we'll just look for `gcc'.  */
  358.   if (p != argv[0])
  359.     {
  360.       *--p = '\0';
  361.       gcc = (char *) malloc ((strlen (argv[0]) + 1 + strlen (GCC_NAME) + 1)
  362.                  * sizeof (char));
  363.       sprintf (gcc, "%s/%s", argv[0], GCC_NAME);
  364.     }
  365. #endif
  366.  
  367.   args = (int *) malloc (argc * sizeof (int));
  368.   bzero (args, argc * sizeof (int));
  369.  
  370.   for (i = 1; i < argc; i++)
  371.     {
  372.       /* If the previous option took an argument, we swallow it here.  */
  373.       if (quote)
  374.     {
  375.       quote = NULL;
  376.       continue;
  377.     }
  378.  
  379.       if (argv[i][0] == '\0' || argv[i][1] == '\0')
  380.     continue;
  381.  
  382.       if (argv[i][0] == '-')
  383.     {
  384.       if (strcmp (argv[i], "-nostdlib") == 0)
  385.         {
  386.           added--;
  387.           library = NULL;
  388.         }
  389.       else if (strcmp (argv[i], "-lm") == 0
  390.            || strcmp (argv[i], "-lmath") == 0)
  391.         args[i] |= MATHLIB;
  392.       else if (strcmp (argv[i], "-v") == 0)
  393.         {
  394.           verbose = 1;
  395.           if (argc == 2)
  396.         {
  397.           /* If they only gave us `-v', don't try to link
  398.              in libg++.  */ 
  399.           added--;
  400.           library = NULL;
  401.         }
  402.         }
  403.       else if (strncmp (argv[i], "-x", 2) == 0)
  404.         saw_speclang = 1;
  405.       else if (((argv[i][2] == '\0'
  406.              && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
  407.             || strcmp (argv[i], "-Tdata") == 0))
  408.         quote = argv[i];
  409.       else if (((argv[i][2] == '\0'
  410.              && (char *) strchr ("cSEM", argv[i][1]) != NULL)
  411.             || strcmp (argv[i], "-MM") == 0))
  412.         {
  413.           /* Don't specify libraries if we won't link, since that would
  414.          cause a warning.  */
  415.           added--;
  416.           library = NULL;
  417.         }
  418.       else
  419.         /* Pass other options through.  */
  420.         continue;
  421.     }
  422.       else
  423.     {
  424.       int len; 
  425.  
  426.       if (saw_speclang)
  427.         continue;
  428.  
  429.       /* If the filename ends in .c or .i, put options around it.
  430.          But not if a specified -x option is currently active.  */
  431.       len = strlen (argv[i]);
  432.       if (len > 2
  433.           && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
  434.           && argv[i][len - 2] == '.')
  435.         {
  436.           args[i] |= LANGSPEC;
  437.           added += 2;
  438.         }
  439.     }
  440.     }
  441.  
  442.   if (quote)
  443.     fatal ("argument to `%s' missing\n", quote);
  444.  
  445.   if (added)
  446.     {
  447.       arglist = (char **) malloc ((argc + added + 1) * sizeof (char *));
  448.  
  449.       for (i = 1, j = 1; i < argc; i++, j++)
  450.     {
  451.       arglist[j] = argv[i];
  452.  
  453.       /* Make sure -lg++ is before the math library, since libg++
  454.          itself uses those math routines.  */
  455.       if (!saw_math && (args[i] & MATHLIB) && library)
  456.         {
  457.           saw_math = 1;
  458.           arglist[j] = library;
  459.           arglist[++j] = argv[i];
  460.         }
  461.  
  462.       /* Wrap foo.c and foo.i files in a language specification to
  463.          force the gcc compiler driver to run cc1plus on them.  */
  464.       if (args[i] & LANGSPEC)
  465.         {
  466.           arglist[j++] = "-xc++";
  467.           arglist[j++] = argv[i];
  468.           arglist[j] = "-xnone";
  469.         }
  470.     }
  471.  
  472.       /* Add `-lg++' if we haven't already done so.  */
  473.       if (library && !saw_math)
  474.     arglist[j++] = library;
  475.  
  476.       arglist[j] = NULL;
  477.     }
  478.   else
  479.     /* No need to copy 'em all.  */
  480.     arglist = argv;
  481.  
  482.   arglist[0] = gcc;
  483.  
  484.   if (verbose)
  485.     {
  486.       if (j == 0)
  487.     j = argc;
  488.  
  489.       for (i = 0; i < j; i++)
  490.     fprintf (stderr, " %s", arglist[i]);
  491.       fprintf (stderr, "\n");
  492.     }
  493. #ifndef OS2
  494. #ifdef __MSDOS__
  495.   run_dos (gcc, arglist);
  496. #else /* !__MSDOS__ */
  497.   if (execvp (gcc, arglist) < 0)
  498.     pfatal_with_name (gcc);
  499. #endif /* __MSDOS__ */
  500. #else /* OS2 */
  501.   if (spawnvp (gcc, arglist) < 0)
  502.     pfatal_with_name (gcc);
  503. #endif
  504.  
  505.   return 0;
  506. }
  507.